/*
 
  Project: DEC加密算法
  File:          pc1crypt.c
                 PC1 加密算法( Pukall Cipher 1 ) 源自 "http://membres.lycos.fr/pc1/"
                 128/256 位密钥
                 为 avr 8 位单片机进行了优化
  Version:       1.0
                  
  Date:          2008.4 
*/
 
#include "Decrypt.h"

static uint16_t ax, bx, cx, dx, inter, cfc, cfd;
static uint16_t si, x1a2;
static uint16_t x1a0[9];

static uint8_t DecryptKey[16];

void DecryptInit(uint8_t  *key)
{
  si = 0;
  x1a2 = 0;
  memcpy(DecryptKey,key,16);
}
 
void exchange(uint16_t *a, uint16_t *b)
{
  uint16_t tmp;
 
  tmp = *a;
  *a = *b;
  *b = tmp;
}
 
void PC1assemble128()
{
 
  uint8_t i;
 
  inter = 0;
  x1a0[0] = 0;
  for(i = 0; i < 8; i++)
  {
	
    x1a0[i + 1] = x1a0[i] ^ ((DecryptKey[i * 2] * 256) + DecryptKey[i * 2 + 1]);
 
    dx = x1a2 + i;
    ax = x1a0[i + 1];
    cx = 0x015A;
    bx = 0x4E35;
 
    exchange(&ax, &si);
    exchange(&ax, &dx);
 
    if (ax != 0)
    {
 
      ax = ax * bx;
     
	}
 
    exchange(&ax, &cx);
 
    if (ax != 0)
    {
 
      ax = ax * si;
      cx = ax + cx;
     
	}
 
    exchange(&ax, &si);
 
    ax = ax * bx;
    dx = cx + dx;
    ax = ax + 1;
 
    x1a2 = dx;
    x1a0[i + 1] = ax;
 
    inter = inter ^ (ax ^ dx);
   
  }
 
}




 
//解密一个字节
uint8_t PC1Dec128Byte(uint8_t c)
{
  uint8_t i;

  PC1assemble128();
  cfc = inter >> 8;
  cfd = inter & 255;
  c = c ^ (cfc ^ cfd);
  
  for(i = 0; i < 16; i++)
  {
    DecryptKey[i] = DecryptKey[i] ^ c;
  }
  return c;
}


//销毁密钥
void DestroyKey()
{
  uint8_t i;
  for(i = 0; i < 16; i++)
  {
    DecryptKey[i] = 0;
  }
}

//加密数据块
void EncryptBlock(uint8_t *key,uint8_t *buf, uint16_t nSize)
{
  	uint16_t n;
  	uint8_t i;

	DecryptInit(key);
	for( n =0;n< nSize; n++)
	{
		PC1assemble128();
		cfc = inter >> 8;
		cfd = inter & 255;
		//
		// difference between encrypt and decrypt
		// if encrypt, need for() then *buf
		// if decrypt, switch turn
		//
		for(i = 0; i < 16; i++)
			DecryptKey[i] = DecryptKey[i] ^ (*buf);

		*buf = *buf ^ (cfc ^ cfd);
		buf++;
	}
	return;
}

//解密数据块
void DecryptBlock(uint8_t *key,uint8_t *buf, uint16_t nSize)
{
  uint16_t n;
  DecryptInit(key);
  for( n = 0; n < nSize; n++)
  {
     buf[n] = PC1Dec128Byte(buf[n]);
  }
	return;
}




